//
//  AppStack.m
//  iCodeMac
//
//  Created by Andrew Barry on 27/02/09.
//  Copyright 2009 Barry Computer Services. All rights reserved.
//

#import "AppStack.h"
#import "FormView.h"
#import "ControlPanel.h"
#import "SourceEditor.h"
#import "AppModule.h"
//#import "FormLoader.h"
#import "FlippedView.h"
//#import "runtime.h"
#import "BlockingView.h"
//#import "JSVirtualMachine.h"

NSMutableArray *gActiveStacks;

@implementation AppStack
+(AppStack *) stackForContext: (JSContext *) cx {
	int idx;
	for (idx = 0; idx < [gActiveStacks count]; idx++) {
		AppStack *s = [gActiveStacks objectAtIndex:idx];
		if (s->cx == cx)
			return s;
	}
	return nil;
}

-(id)initWithPath: (NSString *) p {
	self = [super init];
//	initializeRuntime(self);
	path = [p retain];
	modules = [NSMutableArray new];
//	vm = [[JSVirtualMachine alloc] initWithStack: self];
	undoManager = [NSUndoManager new];
	
	NSFileManager *mgr = [NSFileManager defaultManager];
	NSData *data = [mgr contentsAtPath:path];
	if (data) {
		NSPropertyListFormat fmt;
		NSDictionary *saved = [NSPropertyListSerialization propertyListFromData:data mutabilityOption:NSPropertyListImmutable format:&fmt errorDescription:nil];
		NSArray *savedModules = [saved objectForKey:@"modules"];
		for (int idx = 0; idx < [savedModules count]; idx++) {
			NSDictionary *savedModule = [savedModules objectAtIndex:idx];
			AppModule *m = [[AppModule alloc] initWithStack: self withDefn: savedModule];
			[modules addObject: m];
		}
		currentModule = [modules objectAtIndex:0];
	} else {
		currentModule = [[AppModule alloc] initWithStack: self withDefn: nil];
		[modules addObject: currentModule];
	}

	if (!gActiveStacks)
		gActiveStacks = [NSMutableArray new];
	[gActiveStacks addObject:self];

	return self;
}

-(NSUndoManager *) undoManager {
	return undoManager;
}

-(NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window {
	return undoManager;
}

-(void)propChange: (NSArray *)data {
	id object = [data objectAtIndex:0];
	id val = [data objectAtIndex: 1];
	NSString *key = [data objectAtIndex: 2];
	id oldVal = [object valueForProperty: key];
	
	NSArray *undo = [NSArray arrayWithObjects: object, oldVal, key, nil];
	
	[object setValue: val forProperty:key];
	
	[[self undoManager] registerUndoWithTarget:self selector:@selector(propChange:) object:undo];
}

-(void)showAsWindow {
	if (window == nil) {
		[NSBundle loadNibNamed:@"AppWindow" owner:self];
	}
	[window makeKeyAndOrderFront:self];
	[window setTitle:@"Home"];
	[window setDelegate:self];
}

-(void)switchToEditor {
	NSView *content = [window contentView];
	NSRect bounds = [content bounds];
	isRunning = false;
	if (runView) {
		[runView removeFromSuperview];
		runView = nil;
	}
	if (pauseView) {
		[pauseView removeFromSuperview];
		pauseView = nil;
	}
	[self updateTitle];

	editView = [[FormView alloc] initWithFrame:bounds];
	[content addSubview:editView];
	[editView setAutoresizingMask:  NSViewWidthSizable | NSViewHeightSizable];
	[[editView getFormEditor] setDocument: self];
	if ([currentModule form]) {
		[[editView getFormEditor] loadForm:[currentModule form]];
	}
}

-(bool)switchToRuntime {
	NSView *content = [window contentView];
	
	[self update];
	[self updateTitle];
	[self saveToPath:path];

	// try compilation first
	for (int idx = 0; idx < [modules count]; idx++) {
		AppModule *m = [modules objectAtIndex:idx];
		if (![m compile])
			return false;
	}
		
	if (editView) {
		[editView removeFromSuperview];
		editView = nil;
	}
	runView = [[FlippedView alloc] initWithFrame:[content bounds]];
	[runView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
	[content addSubview:runView];
	
	[window makeKeyAndOrderFront:self];

	isRunning = true;
	[[ControlPanel sharedPanel] hide];

	
	[currentModule runInView:runView];
	return true;
}

-(void)update {
	if (editView) {
		NSMutableDictionary *dict = [[editView getFormEditor] saveForm];
		[currentModule setForm: dict];
	}
	for (int idx = 0; idx < [modules count]; idx++)
		[[modules objectAtIndex:idx] update];
}

-(void)debugRun:(id) sender {
	if (isRunning) {
		[window makeKeyAndOrderFront:self];
		if ([vm isSuspended]) {
			if (pauseView != nil) {
				[pauseView removeFromSuperview];
				pauseView = nil;
				[runView markResumed];
			}
			[vm resume];
		}
	} else {
		[self switchToRuntime];
	}
}

-(void)debugStop: (id) sender {
	if ([vm isSuspended]) {
		[vm stop];
	}
	
	[window setTitle:@"Window"];

	[[ControlPanel sharedPanel] show];
	[self switchToEditor];
}

-(void)updateTitle {
	if (isRunning) {
		if ([vm isSuspended])
			[window setTitle:@"Window - Stopped"];
		else
			[window setTitle:@"Window"];
	} else {
		[window setTitle:@"Window - Edit"];
	}
	
}

-(void)pause {
	if ([vm isRunningVM]) {
		
		NSView *content = [window contentView];
		
		[runView markPaused];
		
		pauseView = [[BlockingView alloc] initWithFrame:[content bounds]];
		[content addSubview:pauseView];
		
		[vm suspend];
	}
}

-(void)editCode: (id) sender {
	[currentModule showCodeEditor];
}

-(void)getInfo: (id) sender {
	if (!isRunning) {
		[[editView getFormEditor] showInfo];
	}
}

-(bool)isRunning {
	return [vm isRunningVM];
}

-(void) errorSheetClose:(NSAlert *)alert returnCode:(int)returnCode contextInfo:(void *)contextInfo {
}

-(void)displayError: (NSString *) message {
	NSAlert *alert = [[NSAlert alloc] init];
	[alert setMessageText:@"An error has occurred"];
	[alert setInformativeText:message];
	[alert addButtonWithTitle:@"Close"];
	[alert setAlertStyle:NSWarningAlertStyle];
	
	[alert beginSheetModalForWindow:window modalDelegate:self didEndSelector:@selector(errorSheetClose:returnCode:contextInfo:) contextInfo:nil];
}

-(void)runtimeErrorMessage: (NSString *) message withReport: (JSErrorReport *) report {
	if (!report->filename) {
		[self displayError: message];
		return;
	}
	
	for (int idx = 0; idx < [modules count]; idx++) {
		AppModule *m = [modules objectAtIndex:idx];
		if (!strcmp(report->filename, [[m scriptId] UTF8String])) {
			[m runtimeErrorMessage: message withReport: report];
		}
	}
}

-(void)saveToPath: (NSString *) path {
	[self update];
	NSMutableDictionary *save = [NSMutableDictionary new];
	NSMutableArray *saveModules = [NSMutableArray new];
	for (int idx = 0; idx < [modules count]; idx++) {
		AppModule *module = [modules objectAtIndex:idx];
		[saveModules addObject:[module save]];
	}
	[save setObject:saveModules forKey:@"modules"];
	NSData *data = [NSPropertyListSerialization dataFromPropertyList:save format:NSPropertyListXMLFormat_v1_0 errorDescription:nil];
	[[NSFileManager defaultManager] createFileAtPath:path contents:data attributes:nil];
}

-(JSVirtualMachine *)vm {
	return vm;
}
@end
